package com.gitee.zhziyun.cnfsystem.master;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.gitee.zhziyun.cnfsystem.config.IpPortConfig;
import com.gitee.zhziyun.cnfsystem.model.Command;
import com.gitee.zhziyun.cnfsystem.model.FileAccept;
import com.gitee.zhziyun.cnfsystem.model.FileSource;
import com.gitee.zhziyun.cnfsystem.model.UserInfo;
import com.gitee.zhziyun.cnfsystem.utils.IpAddressUtil;
import com.gitee.zhziyun.cnfsystem.utils.JSONUtil;
import com.gitee.zhziyun.cnfsystem.utils.udputil.MulticastSender;
import com.gitee.zhziyun.cnfsystem.utils.udputil.UDPSender;
import com.gitee.zhziyun.cnfsystem.works.HeartBeatWorker;
import com.gitee.zhziyun.cnfsystem.works.MessageWorker;
import com.gitee.zhziyun.cnfsystem.works.MulticastWorker;
import com.gitee.zhziyun.cnfsystem.works.Worker;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;


public class AppMasterImpl implements AppMaster {
    private final long startTime;         // 记录进程启动时间
    private final UserInfo userInfo;        // 用户信息
    private boolean running = false;
    private final Map<String, UserInfo> ipUserMap = new LinkedHashMap<>();

    private final Worker heartBeatWorker;   // 自动维护在线用户列表
    private final Worker messageWorker;     // 接收单播消息
    private final Worker multicastWorker;   // 接收组播消息

    private final List<UserStatusListener> userStatusListenerList = new CopyOnWriteArrayList<>();
    private final List<MessageListener> messageListenerList = new CopyOnWriteArrayList<>();
    private final List<MulticastListener> multicastListenerList = new CopyOnWriteArrayList<>();

    public AppMasterImpl(String userName, int userAvatar) {
        this.startTime = System.currentTimeMillis();        // 获取时间戳
        this.userInfo = new UserInfo(userName, userAvatar, IpAddressUtil.getHostname(), IpPortConfig.getReceivePort());

        heartBeatWorker = new HeartBeatWorker(this);
        messageWorker = new MessageWorker(this);
        multicastWorker = new MulticastWorker(this);
    }

    @Override
    public void addMessageListener(MessageListener listener) {
        messageListenerList.add(listener);
    }

    @Override
    public void fireMessage(String ip, String message) {
        for (MessageListener listener : messageListenerList) {
            listener.onMessage(ip, message);
        }
    }

    @Override
    public void fireFileMessage(String ip, FileSource fileSource) {
        for (MessageListener listener : messageListenerList) {
            listener.onFileMessage(ip, fileSource);
        }
    }

    @Override
    public void fireFileAccept(String ip, FileAccept fileAccept) {
        for (MessageListener listener : messageListenerList) {
            listener.onFileAccept(ip, fileAccept);
        }
    }

    @Override
    public void addMulticastListener(MulticastListener listener) {
        multicastListenerList.add(listener);
    }

    @Override
    public void fireMulticastMessage(String ip, String message) {
        for (MulticastListener listener : multicastListenerList) {
            listener.onMulticastMessage(ip, message);
        }
    }

    @Override
    public void fireMulticastFileMessage(String ip, FileSource fileSource) {
        for (MulticastListener listener : multicastListenerList) {
            listener.onMulticastFileMessage(ip, fileSource);
        }
    }

    @Override
    public void fireMulticastFileAccept(String ip, FileAccept fileAccept) {
        for (MulticastListener listener : multicastListenerList) {
            listener.onMulticastFileAccept(ip, fileAccept);
        }
    }


    @Override
    public void addUserStatusListener(UserStatusListener listener) {
        userStatusListenerList.add(listener);
    }

    @Override
    public void fireUserOnline(String ip, UserInfo userInfo) {
        for (UserStatusListener listener : userStatusListenerList) {
            listener.userOnline(ip, userInfo);
        }
    }

    @Override
    public void fireUserOffline(String ip) {
        for (UserStatusListener listener : userStatusListenerList) {
            listener.userOffline(ip);
        }
    }

    @Override
    public UserInfo getUserInfo() {
        return userInfo;
    }

    @Override
    public long getStartTime() {
        return startTime;
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    @Override
    public Map<String, UserInfo> getIpUserMap() {
        return ipUserMap;
    }

    @Override
    public void sendMessageToUser(String message, String receiveIp, int receivePort) throws JsonProcessingException {
        UDPSender.send(receiveIp, receivePort, JSONUtil.objectToString(new Command("message", message)));
    }

    @Override
    public void multicastMessage(String message) throws JsonProcessingException {
        MulticastSender.send(JSONUtil.objectToString(new Command("multicastMessage", message)));
    }

    @Override
    public void sendFileToUser(FileSource fileSource, String receiveIp, int receivePort) throws JsonProcessingException {
        UDPSender.send(receiveIp, receivePort, JSONUtil.objectToString(new Command("file", JSONUtil.objectToString(fileSource))));
    }

    @Override
    public void acceptFile(FileAccept fileAccept, String receiveIp, int receivePort) throws JsonProcessingException {
        UDPSender.send(receiveIp, receivePort, JSONUtil.objectToString(new Command("acceptFile", JSONUtil.objectToString(fileAccept))));
    }

    @Override
    public void multicastFile(FileSource fileSource, String receiveIp, int receivePort) throws JsonProcessingException {
        MulticastSender.send(JSONUtil.objectToString(new Command("multicastFile", JSONUtil.objectToString(fileSource))));
    }

    @Override
    public void multicastAcceptFile(FileAccept fileAccept, String receiveIp, int receivePort) throws JsonProcessingException {
        UDPSender.send(receiveIp, receivePort, JSONUtil.objectToString(new Command("multicastAcceptFile", JSONUtil.objectToString(fileAccept))));
    }

    @Override
    public void start() {
        if (running) {
            System.out.println("主服务已经处于启动状态！");
            return;
        }
        System.out.println("主服务启动");
        running = true;
        heartBeatWorker.start();
        messageWorker.start();
        multicastWorker.start();
    }

    @Override
    public void stop() {
        if (!running) {
            System.out.println("主服务未启动！");
            return;
        }
        running = false;
        heartBeatWorker.stop();
        messageWorker.stop();
        multicastWorker.stop();
    }
}
